<!DOCTYPE html>
<html lang="zh-cn"><head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <link href="/css/main.css" rel="stylesheet">

    <link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />

    <title>Go程序的Defer和追踪 | wiseAI的小站</title>
</head><body><div class="container-fluid">
    <nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-dark">
        <div class="container-fluid">
            <a class="navbar-brand" href="/">
                <img src="/img/favicon.ico" alt="" width="30" height="24" class="d-inline-block align-text-top">
                wiseAI的小站
            </a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/articles/">文章</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/categories/">分类</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/tags/">关键字</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/post/golang/">golang编程</a>
                    </li>
                    
                    <li class="nav-item">
                        <a  class="nav-link"   href="/about/">关于</a>
                    </li>
                    
                </ul>
                <form class="d-flex">
                    <input id="search-query" class="form-control me-2" type="search" placeholder="Search for anything..." aria-label="Search">
                </form>
            </div>
        </div>
    </nav>
</div>




<div id="content">
<div class="container article">
	<h1>Go程序的Defer和追踪</h1>
	<div class="post-meta">
		<div>
			
			
			By wiseai | 2022-07-20 | 3 minutes
		</div>
		<div class="tags">
			
			<a class="btn btn-light links btn-sm" href="/tags/%E7%BC%96%E7%A8%8B/">编程</a>
			
		</div>
	</div>
	<div>
		<div class="article-post">
			<h1 id="64-defer-和追踪">6.4 defer 和追踪</h1>
<p>关键字 <code>defer</code> 允许我们推迟到函数返回之前（或任意位置执行 <code>return</code> 语句之后）一刻才执行某个语句或函数（为什么要在返回之后才执行这些语句？因为 <code>return</code> 语句同样可以包含一些操作，而不是单纯地返回某个值）。</p>
<p>关键字 <code>defer</code> 的用法类似于面向对象编程语言 Java 和 C# 的 finally 语句块，它一般用于释放某些已分配的资源。</p>
<p>示例 6.8 <a href="examples/chapter_6/defer.go">defer.go</a>：</p>
<pre tabindex="0"><code>package main
import &#34;fmt&#34;

func main() {
	function1()
}

func function1() {
	fmt.Printf(&#34;In function1 at the top\n&#34;)
	defer function2()
	fmt.Printf(&#34;In function1 at the bottom!\n&#34;)
}

func function2() {
	fmt.Printf(&#34;Function2: Deferred until the end of the calling function!&#34;)
}
</code></pre><p>输出：</p>
<pre tabindex="0"><code>In Function1 at the top
In Function1 at the bottom!
Function2: Deferred until the end of the calling function!
</code></pre><p>请将 <code>defer</code> 关键字去掉并对比输出结果。</p>
<p>使用 <code>defer</code> 的语句同样可以接受参数，下面这个例子就会在执行 <code>defer</code> 语句时打印 <code>0</code>：</p>
<pre tabindex="0"><code>func a() {
	i := 0
	defer fmt.Println(i)
	i++
	return
}
</code></pre><p>当有多个 <code>defer</code> 行为被注册时，它们会以逆序执行（类似栈，即后进先出）：</p>
<pre tabindex="0"><code>func f() {
	for i := 0; i &lt; 5; i++ {
		defer fmt.Printf(&#34;%d &#34;, i)
	}
}
</code></pre><p>上面的代码将会输出：<code>4 3 2 1 0</code>。</p>
<p>关键字 <code>defer</code> 允许我们进行一些函数执行完成后的收尾工作，例如：</p>
<ol>
<li>关闭文件流 （详见 <a href="12.2.md">第 12.2 节</a>）</li>
</ol>
<pre tabindex="0"><code>// open a file  
defer file.Close()
</code></pre><ol start="2">
<li>解锁一个加锁的资源 （详见 <a href="09.3.md">第 9.3 节</a>）</li>
</ol>
<pre tabindex="0"><code>mu.Lock()  
defer mu.Unlock() 
</code></pre><ol start="3">
<li>打印最终报告</li>
</ol>
<pre tabindex="0"><code>printHeader()  
defer printFooter()
</code></pre><ol start="4">
<li>关闭数据库链接</li>
</ol>
<pre tabindex="0"><code>// open a database connection  
defer disconnectFromDB()
</code></pre><p>合理使用 <code>defer</code> 语句能够使得代码更加简洁。</p>
<p>以下代码模拟了上面描述的第 4 种情况：</p>
<pre tabindex="0"><code>package main

import &#34;fmt&#34;

func main() {
	doDBOperations()
}

func connectToDB() {
	fmt.Println(&#34;ok, connected to db&#34;)
}

func disconnectFromDB() {
	fmt.Println(&#34;ok, disconnected from db&#34;)
}

func doDBOperations() {
	connectToDB()
	fmt.Println(&#34;Defering the database disconnect.&#34;)
	defer disconnectFromDB() //function called here with defer
	fmt.Println(&#34;Doing some DB operations ...&#34;)
	fmt.Println(&#34;Oops! some crash or network error ...&#34;)
	fmt.Println(&#34;Returning from function here!&#34;)
	return //terminate the program
	// deferred function executed here just before actually returning, even if
	// there is a return or abnormal termination before
}
</code></pre><p>输出：</p>
<pre tabindex="0"><code>ok, connected to db
Defering the database disconnect.
Doing some DB operations ...
Oops! some crash or network error ...
Returning from function here!
ok, disconnected from db
</code></pre><p><strong>使用 <code>defer</code> 语句实现代码追踪</strong></p>
<p>一个基础但十分实用的实现代码执行追踪的方案就是在进入和离开某个函数打印相关的消息，即可以提炼为下面两个函数：</p>
<pre tabindex="0"><code>func trace(s string) { fmt.Println(&#34;entering:&#34;, s) }
func untrace(s string) { fmt.Println(&#34;leaving:&#34;, s) }
</code></pre><p>以下代码展示了何时调用这两个函数：</p>
<p>示例 6.10 <a href="examples/chapter_6/defer_tracing.go">defer_tracing.go</a>:</p>
<pre tabindex="0"><code>package main

import &#34;fmt&#34;

func trace(s string)   { fmt.Println(&#34;entering:&#34;, s) }
func untrace(s string) { fmt.Println(&#34;leaving:&#34;, s) }

func a() {
	trace(&#34;a&#34;)
	defer untrace(&#34;a&#34;)
	fmt.Println(&#34;in a&#34;)
}

func b() {
	trace(&#34;b&#34;)
	defer untrace(&#34;b&#34;)
	fmt.Println(&#34;in b&#34;)
	a()
}

func main() {
	b()
}
</code></pre><p>输出：</p>
<pre tabindex="0"><code>entering: b
in b
entering: a
in a
leaving: a
leaving: b
</code></pre><p>上面的代码还可以修改为更加简便的版本（示例 6.11 <a href="examples/chapter_6/defer_tracing2.go">defer_tracing2.go</a>）：</p>
<pre tabindex="0"><code>package main

import &#34;fmt&#34;

func trace(s string) string {
	fmt.Println(&#34;entering:&#34;, s)
	return s
}

func un(s string) {
	fmt.Println(&#34;leaving:&#34;, s)
}

func a() {
	defer un(trace(&#34;a&#34;))
	fmt.Println(&#34;in a&#34;)
}

func b() {
	defer un(trace(&#34;b&#34;))
	fmt.Println(&#34;in b&#34;)
	a()
}

func main() {
	b()
}
</code></pre><p><strong>使用 <code>defer</code> 语句来记录函数的参数与返回值</strong></p>
<p>下面的代码展示了另一种在调试时使用 <code>defer</code> 语句的手法（示例 6.12 <a href="examples/chapter_6/defer_logvalues.go">defer_logvalues.go</a>）：</p>
<pre tabindex="0"><code>package main

import (
	&#34;io&#34;
	&#34;log&#34;
)

func func1(s string) (n int, err error) {
	defer func() {
		log.Printf(&#34;func1(%q) = %d, %v&#34;, s, n, err)
	}()
	return 7, io.EOF
}

func main() {
	func1(&#34;Go&#34;)
}
</code></pre><p>输出：</p>
<pre><code>Output: 2011/10/04 10:46:11 func1(&quot;Go&quot;) = 7, EOF</code></pre>

		</div>
	</div>
</div>


<div class="container">
    
    <div class="row">
        
        <div class="col-5">
            <a class="page-link link-dark text-end dh" href="/post/golang/2022.07.19-%E4%BC%A0%E9%80%92%E5%8F%98%E9%95%BF%E5%8F%82%E6%95%B0/">
                <h5>前一篇</h5><br>
                Go程序传递变长参数
            </a>            
        </div>
        
        <div class="col-2">
        </div>
        
        <div class="col-5">
            <a class="page-link link-dark text-start dh" href="/post/golang/2022.07.21-%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0/">
                <h5>后一篇</h5><br>
                Go程序的内置函数
            </a>            
        </div>
        
    </div>
    
</div>

        </div><br><br>
<footer class="container">
    <h2>友情链接</h2>
    <hr>
    <nav class="nav nav-pills flex-column flex-sm-row">
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/gnzg/index.html" target="_blank">孤鸟之歌</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/mm/index.html" target="_blank">生成随机字符</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/md/index.html" target="_blank">MarkDown</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://gitee.com/" target="_blank">Gitee</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://github.com/" target="_blank">Github</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.aliyun.com/" target="_blank">阿里云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://cloud.tencent.com/" target="_blank">腾讯云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.oschina.net/" target="_blank">OSCHINA开源中国</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://gitee.com/wiseai/the-way-to-go_ZH_CN/blob/master/eBook/directory.md" target="_blank">the way to go</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://topgoer.com/" target="_blank">golang文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://goframe.org/display/gf" target="_blank">GoFrame</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.aliyundrive.com/" target="_blank">阿里云盘</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://cn.vuejs.org/" target="_blank">vue3文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://element-plus.gitee.io/zh-CN/" target="_blank">element-plus文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.runoob.com/vue3/vue3-tutorial.html" target="_blank">vue3菜鸟教程</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://v5.bootcss.com/" target="_blank">bootstrap v5 中文文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.bootstrap.cn/" target="_blank">bootstrap文档</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://caddy2.dengxiaolong.com/docs/" target="_blank">caddy中文教程</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.58pic.com/" target="_blank">千图</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://ifonts.com/" target="_blank">iFonts</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://marketing.qiniu.com/" target="_blank">七牛云</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.ixigua.com/" target="_blank">西瓜视频</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/yugang/index.html" target="_blank">鱼缸计算</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://justcc.mengkang.net/#/" target="_blank">C语言JustCC</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://wiseai.gitee.io/pages/pptist/" target="_blank">PPTist</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="/index.xml" target="_blank">RSS</a>
        
        <a class="flex-sm-fill text-sm-center nav-link links link-dark" href="https://www.kancloud.cn/idcpj/python/418553" target="_blank">参考资料</a>
        
    </nav>

    <div class="copyright text-center">
      <span class="power-by">
        Powered by <a class="links" href="https://gohugo.io" target="_blank">Hugo</a>
    </span>
    <span>|</span>
    <span>
        Theme - <a class="links" href="https://github.com/wiseai-go/blog-hugo" target="_blank">WiseAI</a>
    </span>
    <br>
    <span class="copyright-year">
        &copy;
        
        2017 -
        2023<span>
            陇ICP备15000157号
            
        </span></span>

</div>
</footer>
<script src="/js/bootstrap.bundle.min.js"></script>


</body>
</html>
